#include "datastruct.h"
#include <pthread.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <netdb.h>

/*打印级别列表*/
#define EXIT -1   //强制让某个客户端下线
#define INFO 1    //打印服务器端口
#define DEBUG 2   //打印客户发送内容
#define WARNING 3 //警告信息
#define ERR 4     //错误信息
#define GETUSER 6 //获取用户信息
#define GETSTAT 9 //获取服务器状态信息

#define BUFFSIZE 20

/*全局变量，用于设置打印级别*/
int global = 3;

/*表驱动结构体*/
typedef struct _levelHandler{
    int t_level;
    void (*pfun)(int, void *);
} Level_handler;

/*INFO打印级别，用于打印服务器端口、IP*/
void finfo(int temp_global, void* input);
/*DEBUG打印级别，用于打印其中一个在线客户端发送的消息内容*/
void fdebug(int temp_global, void* input);
/*WARNING打印级别，用于打印警告信息*/
void fwarning(int temp_global, void* input);
/*ERR打印级别，用于打印错误信息，并且退出*/
void ferr(int temp_global, void* input);
/*获取在线所有用户的用户名*/
void fgetuser(int temp_global, void* input);
/*强制让某个客户端下线*/
void fexit(int temp_global, void* input);
/*获取服务器的状态信息*/
void fgetstat(int temp_global, void* input);

/*表驱动结构体数组列表*/
Level_handler print_lev[] = {
        {-1, fexit},
		{1, finfo},
		{2, fdebug},
		{3, fwarning},
		{4, ferr},
		{6, fgetuser},
		{9, fgetstat}
	};

/*ss调试线程*/
void *ss_debug(void *arg)
{
    int *t_shm = (int *)arg;
    while(1)
    {
        sleep(1);
        global = *t_shm;
        //printf("thread global : %d\n", global);
    } 
    return NULL;
}

int main()
{
    key_t key;
    int shmid;
    int *shmaddr = NULL;

    printf("before global : %d\n", global);

    key = ftok("./", 802);
    if(key < 0)
    {
        err_sys("ftok error");
    }

    shmid = shmget(key, BUFFSIZE, IPC_CREAT | 0666);
    if(shmid == -1)
    {
        err_sys("shmget error");
    }

    shmaddr = shmat(shmid, NULL, 0);
    printf("shmaddr addr : %p\n", shmaddr);
    if(shmaddr < 0)
    {
        err_sys("shmat error");
    }
    printf("shmaddr data :%d\n",*shmaddr);

    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd < 0)
    {
        err_sys("socket error");
    }

    int sockopt = 1;
    if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt)) < 0)
    {
        err_sys("setsockopt error");
    }

    struct sockaddr_in my_addr;
    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(8080);
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    int ret = bind(sockfd, (struct sockaddr *)&my_addr, sizeof(my_addr));
    if(ret != 0)
    {
        err_sys("bind error");
    }

    ret = listen(sockfd, 5);
    if(ret != 0)
    {
        err_sys("listen error");
    }











/*测试*/
/**************************************************************************************************************/
    pthread_t tid;
    pthread_create(&tid, NULL, ss_debug, (void *)shmaddr);
    pthread_detach(tid);

    sleep(1);//等待线程响应

    printf("global after thread : %d\n", global);
    if(global == 1)
    {
        printf("info level\n");
    }

    do
    {
        sleep(1);
        printf("waiting ...\n");
        print_lev[1].pfun(global, (void *)&my_addr);
        sleep(2);
        break;
    }while(global != 1);

    int i = 0;
    while(i < 5)
    {
        sleep(1);
        printf("global : %d\n", global);
        printf("err level ...\n");
        print_lev[3].pfun(global, "hello error");
        i++;
    }
  
    //char send_buf[1024] = {0};
    char recv_buf[1024] = {0};

    printf("listening ...\n");

    while(1)
    {
        int connfd;
        struct sockaddr_in client_addr;
        char client_ip[INET_ADDRSTRLEN] = {0};
        socklen_t client_len = sizeof(client_ip);
        int recv_len;
        connfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_len);

        inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN);

        while(1)
        {
            recv_len = recv(connfd, recv_buf, sizeof(recv_buf), 0);  
            printf("Recv data(%d) : %s\n", recv_len, recv_buf);
            print_lev[2].pfun(global, (void *)recv_buf);
            if(global == EXIT)
            {
                print_lev[0].pfun(global, (void *)&connfd);
                break;
            }
        }
    }
/**************************************************************************************************************/





     /*用于直接在程序中删除共享内存*/
    char temp_test;
    printf("Do you want to delete the share memory ? (y or n)\n");
    scanf("%c", &temp_test);
    if('y' == temp_test)
    {
        ret = shmdt(shmaddr);
        if(ret == -1)
        {
            err_sys("shmdt error");
        }
        ret = shmctl(shmid, IPC_RMID, NULL);
        if(ret == -1)
        {
            err_sys("shmctl error");
        }
    }

    close(sockfd);
    return 0;
}

/*INFO打印级别，用于打印服务器端口、IP*/
void finfo(int temp_global, void* input)
{
    if(INFO == temp_global)
    {
        printf("Current print level number : %d\n", temp_global);
        struct sockaddr_in *temp_addr = (struct sockaddr_in *)input;
        char current_ip[INET_ADDRSTRLEN] = {0};
        inet_ntop(AF_INET, &temp_addr->sin_addr, current_ip, INET_ADDRSTRLEN);
        printf("Server IP : %s\n", current_ip);
        printf("Server Port : %d\n", ntohs(temp_addr->sin_port));
    }	
}
/*DEBUG打印级别，用于打印其中一个在线客户端发送的消息内容*/
void fdebug(int temp_global, void* input)
{
    if(DEBUG == temp_global)
    {
        printf("Current print level number : %d\n", temp_global);
        char *temp_buf = (char *)input;
        printf("Recv data : %s\n", temp_buf);
    }
}
/*WARNING打印级别，用于打印警告信息*/
void fwarning(int temp_global, void* input)
{
    if(WARNING == temp_global)
    {
        printf("Current print level number : %d\n", temp_global);
        char *temp_buf = (char *)input;
        printf("WARNING : %s\n", temp_buf);
    }
}
/*ERR打印级别，用于打印错误信息，并且退出*/
void ferr(int temp_global, void* input)
{
    if(ERR == temp_global)
    {
        printf("Current print level number : %d\n", temp_global);
        char *temp_buf = (char *)input;
        printf("Error : %s\n", temp_buf);
        exit(0);
    }
}
/*获取在线所有用户的用户名*/
void fgetuser(int temp_global, void* input)
{

}
/*强制让某个客户端下线*/
void fexit(int temp_global, void* input)
{
    if(EXIT == temp_global)
    {
        //sleep(1);
        printf("\nCurrent print level number : %d\n", temp_global);
        int *temp_buf = (int *)input;
        printf("Close Client : %d\n", *temp_buf);
        close(*temp_buf);
        printf("Client has closed !\n");
    }
}
/*获取服务器的状态信息*/
void fgetstat(int temp_global, void* input)
{

}